#include "app_module.h"
#include "ace_log.h"
#include "js_app_context.h"
#if (FEATURE_SCREEN_ON_VISIBLE == 1)
#include "js_async_work.h"
#include "product_adapter.h"
#endif

#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"

#define LED_SERVICE "HDF_GENERIC_LED"
#define LED_WRITE_READ_BY_GPIO_NUM 1  // 读写操作码，通过GPIO编号指定
#define LED_WRITE_READ_BY_LABEL 2     // 读写操作码，通过led的label指定
#define LED_WRITE_READ_BY_ORDER 3     // 读写操作码，通过注册顺序指定

// #define LED_DEBUG

namespace OHOS {
namespace ACELite {

#define PACKAGE_SBUF_DATA_TO_UINT64(data, num, led_status, sent_data) data[0] = led_status; \
																			memcpy(data + 4, &num, 4); \
																			if (!HdfSbufWriteUint64(sent_data, *((uint64_t*)data))) { \
																				printf("fail to write sbuf!\r\n"); \
																				return EXIT_FAILURE; \
																			}

/*
 * @brief: 将信息打包成uint64结构
 * 下面是格式：
 * 方式1 使用gpionum指定，64bit的数据，第1个字节为 LedStatus, 后4个字节是用于指定的gpionum
 * 方式2 使用label指定，传递字符串，字符串第一个字符是'0' '1' '2' 对应 LedStatus，之后就是label
 * 方式3 使用注册顺序指定，64bit的数据，第1个字节为 LedStatus, 后4个字节是用于指定的注册顺序（从0开始）
 */
static int led_dispatch_package_sbuf_data(uint8_t cmd_code, char* led_desc, int num, uint8_t led_status, struct HdfSBuf *sent_data)
{
	char* data;

	data = NULL;
	if (cmd_code == LED_WRITE_READ_BY_GPIO_NUM)
	{
		data = (char*)calloc(sizeof(char), 8);
		PACKAGE_SBUF_DATA_TO_UINT64(data, num, led_status, sent_data);
	}
	else if (cmd_code == LED_WRITE_READ_BY_LABEL)
	{
		int desc_len;
		desc_len = strlen(led_desc);

		data = (char*)calloc(sizeof(char), 1 + desc_len + 1); // led_status + led_desc + '\0'

		data[0] = '0' + led_status;
		memcpy(data + 1, led_desc, desc_len);

		// 64bit的数据写入 Sbuf
		if (!HdfSbufWriteString(sent_data, data))
		{
			printf("fail to write sbuf!\r\n");
			return EXIT_FAILURE;
		}
	}
	else if (cmd_code == LED_WRITE_READ_BY_ORDER)
	{
		data = (char*)calloc(sizeof(char), 8);
		PACKAGE_SBUF_DATA_TO_UINT64(data, num, led_status, sent_data);
	}
	if (!data)
	{
		return EXIT_FAILURE;
	}
	free(data);
	data = NULL;

	return EXIT_SUCCESS;
}

/*
 * @brief: 设置LED灯的状态，和调用Dispatch调用驱动能力
 * @param: serv: 用于调用对应驱动Dispatch
 * @param: cmd_code: 对应驱动Dispatch的cmd_code
 * @param: led_desc: 打包成HdfSBuf的字符串
 * @param: num: led灯的编号或者gpio编号
 * @param: led_status: 要设置的led灯的状态
 * @param: val: 返回设置后led灯的状态
 * @return: 执行状态 HDF_SUCCESS 代表执行成功
 */
static int led_status_setup(struct HdfIoService *serv, int32_t cmd_code, char* led_desc, int32_t num, int32_t led_status, int32_t *val)
{
	int ret = HDF_FAILURE;
	struct HdfSBuf *sent_data = HdfSbufObtainDefaultSize();
	struct HdfSBuf *reply_data = HdfSbufObtainDefaultSize();

	if (sent_data == NULL || reply_data == NULL) {
		HILOG_ERROR(HILOG_MODULE_ACE,"fail to obtain sbuf sent_data\n");
		return ret;
	}

	ret = led_dispatch_package_sbuf_data(cmd_code, led_desc, num, led_status, sent_data);
	if (ret)
	{
		HILOG_ERROR(HILOG_MODULE_ACE,"fail to package sent_data\n");
		HdfSbufRecycle(sent_data);
		HdfSbufRecycle(reply_data);
		return HDF_FAILURE;
	}

	// 调用 Dispatch 函数，控制 LED
	ret = serv->dispatcher->Dispatch(&serv->object, cmd_code, sent_data, reply_data);
	if (ret != HDF_SUCCESS)
	{
		HILOG_ERROR(HILOG_MODULE_ACE,"fail to send service call\n");
		HdfSbufRecycle(sent_data);
		HdfSbufRecycle(reply_data);
		return ret;
	}
	if (!HdfSbufReadInt32(reply_data, val))
	{
		HILOG_ERROR(HILOG_MODULE_ACE,"fail to get service call reply_data\n");
		ret = HDF_ERR_INVALID_OBJECT;
		HdfSbufRecycle(sent_data);
		HdfSbufRecycle(reply_data);
		return ret;
	}
#ifdef LED_DEBUG
	HILOG_INFO(HILOG_MODULE_ACE,"led %s\n", val[0] ? "ON" : "OFF");
#endif

	HdfSbufRecycle(sent_data);
	HdfSbufRecycle(reply_data);
	return ret;
}

// 执行失败时，开始回调函数，然后函数返回
#define CONTROL_LED_FAILED_HANDLE JSI::CallFunction(fail, thisVal, nullptr, 0); \
									JSI::CallFunction(complete, thisVal, nullptr, 0); \
									JSI::ReleaseValueList(success, fail, complete); \
									return JSI::CreateUndefined();

/*
 * @brief: JS执行态 ledcontrole 执行时实际执行的函数
 */
JSIValue AppModule::ControlLed(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
{
	struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE);
	if (serv == NULL)
	{
		HILOG_ERROR(HILOG_MODULE_ACE,"fail to get service2 %s\n", LED_SERVICE);
		return JSI::CreateUndefined();
	}

	if ((args == nullptr) || (argsNum == 0) || (JSI::ValueIsUndefined(args[0]))) {
		return JSI::CreateUndefined();
	}

	// 三个回调函数
	JSIValue success = JSI::GetNamedProperty(args[0], CB_SUCCESS); // 执行成功的回调函数
	JSIValue fail = JSI::GetNamedProperty(args[0], CB_FAIL); // 执行失败的回调函数
	JSIValue complete = JSI::GetNamedProperty(args[0], CB_COMPLETE); // 执行完毕的回调函数

	/*
	* handle_type
	* led_status
	* num
	* led_desc
	* 其中 handle_type 和 led_status 应该存在
	* handle_type = 1 或者 3 代表 num 是 gpio编号 或者 注册顺序 。此时 led_desc 可以不提供
	* handle_type = 2 代表 led_desc 是 LED 的 label 。此时 num 可以不提供
	*
	*/
	int32_t handle_type = (int32_t)JSI::GetNumberProperty(args[0], "handle_type");
	int32_t led_status = (int32_t)JSI::GetNumberProperty(args[0], "led_status");

	// 解析 led_desc 参数（可选）
	char* led_desc = NULL;
	bool hasLedDesc = false;
	size_t value_len = 0;
	char* led_desc_temp;
	JSIValue ledDescValue = JSI::GetNamedProperty(args[0], "led_desc");
	if (!JSI::ValueIsUndefined(ledDescValue) && JSI::ValueIsString(ledDescValue)) {
		led_desc_temp = JSI::ValueToStringWithBufferSize(ledDescValue, value_len);
		if (value_len > 0) {
			led_desc = (char*)calloc(sizeof(char), value_len + 1);
			memcpy(led_desc, led_desc_temp, value_len);
			hasLedDesc = true;
		}
		JSI::ReleaseString(led_desc_temp);
	}

	// 解析 num 参数（可选）
	int32_t num = 0;
	bool hasNum = false;
	JSIValue numValue = JSI::GetNamedProperty(args[0], "num");
	if (!JSI::ValueIsUndefined(numValue) && JSI::ValueIsNumber(numValue)) {
		num = (int32_t)JSI::GetNumberProperty(args[0], "num");
		hasNum = true;
	}

	// 检查至少提供 led_desc 或 num 中的一个
	if (!hasLedDesc && !hasNum) {
		HILOG_ERROR(HILOG_MODULE_ACE, "Either led_desc or num must be provided\n");
		CONTROL_LED_FAILED_HANDLE
	}

	if (handle_type == 1 && !hasNum) {
		HILOG_ERROR(HILOG_MODULE_ACE, "handle type 1 need a gpio num to match led\n");
		CONTROL_LED_FAILED_HANDLE
	}

	if (handle_type == 2 && !hasLedDesc) {
		HILOG_ERROR(HILOG_MODULE_ACE, "handle type 2 need a led_desc to match led\n");
		CONTROL_LED_FAILED_HANDLE
	}

	if (handle_type == 3 && !hasNum) {
		HILOG_ERROR(HILOG_MODULE_ACE, "handle type 1 need a led num to match led\n");
		CONTROL_LED_FAILED_HANDLE
	}

	int32_t replyData = 0;

	int ret;
	ret = led_status_setup(serv, handle_type, led_desc, num, led_status, &replyData);
	free(led_desc);
	led_desc = NULL;
	if (ret)
	{
		HILOG_ERROR(HILOG_MODULE_ACE,"fail to send event\n");
		CONTROL_LED_FAILED_HANDLE
	}

	// success 函数的参数1是当前LED的状态 1 点亮 0 熄灭
	JSIValue result = JSI::CreateObject();
	JSI::SetNumberProperty(result, "led_status", replyData);

	JSIValue argv[ARGC_ONE] = {result};
	JSI::CallFunction(success, thisVal, argv, ARGC_ONE);
	JSI::CallFunction(complete, thisVal, nullptr, 0);
	JSI::ReleaseValueList(success, fail, complete, result);

	HdfIoServiceRecycle(serv);

	return JSI::CreateUndefined();
}
} // end of ACELite
} // end of OHOS
